import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/*
 * @lc app=leetcode.cn id=208 lang=java
 *
 * [208] 实现 Trie (前缀树)
 *
 * https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/
 *
 * algorithms
 * Medium (63.15%)
 * Likes:    169
 * Dislikes: 0
 * Total Accepted:    19K
 * Total Submissions: 30.1K
 * Testcase Example:  '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]'
 *
 * 实现一个 Trie (前缀树)，包含 insert, search, 和 startsWith 这三个操作。
 *
 * 示例:
 *
 * Trie trie = new Trie();
 *
 * trie.insert("apple");
 * trie.search("apple");   // 返回 true
 * trie.search("app");     // 返回 false
 * trie.startsWith("app"); // 返回 true
 * trie.insert("app");
 * trie.search("app");     // 返回 true
 *
 * 说明:
 *
 *
 * 你可以假设所有的输入都是由小写字母 a-z 构成的。
 * 保证所有输入均为非空字符串。
 *
 *
 */

// @lc code=start


class Trie {

    private Node root;

        class Node{
        private boolean isEnd;
        private Map<Character, Node> next;

        public Node() {
            this.isEnd = false;
            this.next = new HashMap<>();
        }

        public void insert(String s) {
            if(s.length() == 0) {
                this.isEnd = true;
                return;
            }
            char ch = s.charAt(0);
            if(!this.next.containsKey(ch)) {
                this.next.put(ch, new Node());
            }
            Node next = this.next.get(ch);
            next.insert(s.substring(1));

        }

        public boolean search(String s) {

            if(s.length() == 0) {
                return this.isEnd ? true : false;
            }
            char ch = s.charAt(0);

            if(!this.next.containsKey(ch)) {

                return false;
            }
            Node next = this.next.get(ch);
            return next.search(s.substring(1));
        }

        public boolean startsWith(String s) {

            if(s.length() == 0) {
                return true;
            }
            char ch = s.charAt(0);
            if(!this.next.containsKey(ch)) {

                return false;
            }
            Node next = this.next.get(ch);

            return next.startsWith(s.substring(1));
        }


    }

    /** Initialize your data structure here. */
    public Trie() {
        root = new Node();
    }

    /** Inserts a word into the trie. */
    public void insert(String word) {
        root.insert(word);
    }

    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        return root.search(word);
    }

    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return root.startsWith(prefix);
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */
// @lc code=end

